home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
machserver
/
1.098
/
mach
/
sun4c.md
/
div.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-17
|
11KB
|
414 lines
#ifndef lint
static char sccsid[] = "@(#)div.c 1.6 88/02/08 SMI";
#endif
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*
* This whole file refuses to lint.
*/
#ifndef lint
#include <sun4/fpu/fpu_simulator.h>
#include <sun4/fpu/globals.h>
PRIVATE unsigned
trial_quotient(remainder, divisor)
unsigned remainder[], divisor[];
/*
* Given remainder[0,1,2,3,4] < 2**16, divisor[0,1,2,3] < 2**16, 2**15 <=
* divisor[0] < 2**16, computes a trial quotient q < 2**17, such that q =
* remainder/divisor, and revises remainder.
*/
{
unsigned q;
int i, k;
unsigned t, t1, t2;
q = ((remainder[0] << 16) + remainder[1]) / divisor[0];
for (i = 3; i >= 0; i--) {
t = (q & 0xffff) * divisor[i];
t1 = t >> 16;
t2 = t & 0xffff;
if (remainder[i + 1] < t2) { /* ripple carry */
k = i;
while ((k >= 0) && (remainder[k] == 0))
remainder[k--] = 0xffff;
remainder[k]--;
}
remainder[i + 1] -= t2;
remainder[i + 1] &= 0xffff;
if ((i >= 1) && (remainder[i] < t1)) { /* ripple carry */
k = i - 1;
while ((k >= 0) && (remainder[k] == 0))
remainder[k--] = 0xffff;
remainder[k]--;
}
remainder[i] -= t1;
remainder[i] &= 0xffff;
t = (q >> 16) * divisor[i];
if (t > 0) {
if ((i >= 1) && (remainder[i] < t)) { /* ripple carry */
k = i - 1;
while ((k >= 0) && (remainder[k] == 0))
remainder[k--] = 0xffff;
remainder[k]--;
}
remainder[i] -= t;
remainder[i] &= 0xffff;
}
}
while (remainder[0] > 0x8000) { /* Sign reversal occurred - reduce
* quotient by 1 - add divisor back
* to remainder. */
q--;
for (i = 3; i >= 0; i--) {
if (remainder[i + 1] > (0xffff - divisor[i])) { /* ripple carry */
k = i;
while ((k >= 0) && (remainder[k] == 0xffff))
remainder[k--] = 0;
if (k >= 0)
remainder[k]++;
}
remainder[i + 1] += divisor[i];
remainder[i + 1] &= 0xffff;
}
}
/* Make sure that remainder <= divisor. */
i = 0;
while (remainder[i + 1] == divisor[i])
i++;
if ((remainder[0] != 0) || (i > 3) || (remainder[i + 1] > divisor[i])) { /* Remainder too big -
* increase quotient by
* 1 - subtract divisor
* back from remainder. */
q++;
for (i = 3; i >= 0; i--) {
if (remainder[i + 1] < divisor[i]) { /* ripple carry */
k = i;
while ((k >= 0) && (remainder[k] == 0))
remainder[k--] = 0xffff;
if (k >= 0)
remainder[k]--;
}
remainder[i + 1] -= divisor[i];
remainder[i + 1] &= 0xffff;
}
i = 0;
while (remainder[i] == divisor[i])
i++;
}
for (i = 0; i <= 3; i++)
remainder[i] = remainder[i + 1];
remainder[4] = 0;
return q;
}
void
_fp_div(px, py, pz)
unpacked *px, *py, *pz;
{
unsigned quotient[5]; /* Quotient accumulator. */
unsigned remainder[5]; /* Remainder accumulator. */
unsigned divisor[5];
*pz = *px;
pz->sign = px->sign ^ py->sign;
if ((py->fpclass == fp_quiet) || (py->fpclass == fp_signaling)) {
*pz = *py;
return;
}
switch (px->fpclass) {
case fp_quiet:
case fp_signaling:
return;
case fp_zero:
case fp_infinity:
if (px->fpclass == py->fpclass) { /* 0/0 or inf/inf */
fpu_error_nan(pz);
pz->fpclass = fp_quiet;
}
return;
case fp_normal:
switch (py->fpclass) {
case fp_zero: /* number/0 */
fpu_set_exception(fp_division);
pz->fpclass = fp_infinity;
return;
case fp_infinity: /* number/inf */
pz->fpclass = fp_zero;
return;
}
}
/* Now x and y are both normal or subnormal. */
pz->exponent = px->exponent - py->exponent;
remainder[0] = px->significand[0] >> 16;
remainder[1] = px->significand[0] & 0xffff;
remainder[2] = px->significand[1] >> 16;
remainder[3] = px->significand[1] & 0xffff;
remainder[4] = 0;
divisor[0] = py->significand[0] >> 16;
divisor[1] = py->significand[0] & 0xffff;
divisor[2] = py->significand[1] >> 16;
divisor[3] = py->significand[1] & 0xffff;
divisor[4] = 0;
quotient[0] = trial_quotient(remainder, divisor);
quotient[1] = trial_quotient(remainder, divisor);
pz->significand[0] = (quotient[0] << 16) + quotient[1];
quotient[2] = trial_quotient(remainder, divisor);
quotient[3] = trial_quotient(remainder, divisor);
pz->significand[1] = (quotient[2] << 16) + quotient[3];
if (quotient[2] > 0xffff)
pz->significand[0]++;
if (remainder[0] >= 0x8000) { /* remainder is large enough to force
* round upward. */
pz->significand[2] = 0xc0000000;
} else { /* Remainder < 1.0 <= divisor so compare
* 2*remainder to divisor. */
int i;
for (i = 0; i <= 3; i++) {
remainder[i] <<= 1;
if (remainder[i] >= 0x10000) { /* Shift out. */
remainder[i] &= 0xffff;
remainder[i - 1] |= 1;
}
}
for (i = 0; i <= 3; i++) { /* compare divisor to
* 2*remainder */
if (divisor[i] > remainder[i])
goto gt;
if (divisor[i] < remainder[i])
goto lt;
}
/*
* Can't fall through to here - remainder can't be exactly
* half divisor.
*/
gt: /* divisor is greater than 2 * remainder */
pz->significand[2] = remainder[0] | remainder[1] | remainder[2] | remainder[3];
if (pz->significand[2] & 1)
pz->significand[2] |= 1; /* Save lsb. */
pz->significand[2] >>= 1; /* Right shift for leading 0
* round bit; rest of word
* will be zero if remainder
* is exactly zero. */
goto round;
lt: /* divisor is less than 2 * remainder. */
pz->significand[2] = 0xc0000000; /* Therefore round
* upward. */
goto round;
}
round:
if (quotient[0] > 0xffff) { /* 1 <= quotient < 2 */
fpu_rightshift(pz, 1);
pz->significand[0] |= 0x80000000;
} else
/* 0.5 <= quotient < 1 */
pz->exponent--;
}
#define ADDBIT(X,I) /* Adds 2**-i to x, an array of 16-bit chunks. */ \
(X)[((I)-1) / 16] += 0x8000 >> ((I-1) % 16)
#define SUBBIT(X,I) /* Adds -2**-i to x, an array of 16-bit chunks. */ \
(X)[((I)-1) / 16] -= 0x8000 >> ((I-1) % 16)
PRIVATE
dosqrt(px, pz)
unpacked *px, *pz;
{
int i, j, negative, borrow;
unsigned quotient[5]; /* Quotient accumulator. */
unsigned remainder[5]; /* Remainder accumulator. */
for (i = 0; i <= 4; i++) {
quotient[i] = 0;
}
remainder[0] = (px->significand[0] - 0x40000000) >> 16;
remainder[1] = px->significand[0] & 0xffff;
remainder[2] = px->significand[1] >> 16;
remainder[3] = px->significand[1] & 0xffff;
remainder[4] = px->significand[2] >> 16;
negative = 0;
for (i = 1; i <= 65; i++) { /* Generate one more bit of quotient. */
for (j = 0; j <= 4; j++) { /* Double remainder. */
remainder[j] <<= 1;
}
if (negative) { /* Remainder was negative - add quotient. */
for (j = 0; j <= 4; j++) {
remainder[j] -= quotient[j];
}
SUBBIT(remainder, i + 1);
SUBBIT(remainder, i + 2);
for (j = 4; j >= 1; j--) { /* Force
* borrows/carries. */
while (remainder[j] > 0x20000) {
remainder[j] += 0x10000;
remainder[j - 1] -= 1;
}
while (remainder[j] > 0xffff) {
remainder[j] -= 0x10000;
remainder[j - 1] += 1;
}
}
borrow = 0;
while (remainder[0] > 0xffff) {
remainder[0] += 0x10000;
borrow++;
}
if ((remainder[0] | remainder[1] | remainder[2] | remainder[3] | remainder[4]) == 0) { /* Remainder is exactly
* zero. */
negative = 0;
} else if (borrow) { /* Remainder has changed
* sign. */
negative = 0;
j = 4;
while (remainder[j] == 0)
j--;
remainder[j] = 0x10000 - remainder[j];
for (j--; j >= 0; j--) { /* Complement remainder. */
remainder[j] = 0xffff - remainder[j];
}
}
} else { /* Remainder is positive - subtract quotient. */
ADDBIT(quotient, i); /* Adjust quotient. */
for (j = 0; j <= 4; j++) {
remainder[j] -= quotient[j];
}
SUBBIT(remainder, i + 2);
for (j = 4; j >= 1; j--) { /* Force
* borrows/carries. */
while (remainder[j] > 0x20000) {
remainder[j] += 0x10000;
remainder[j - 1] -= 1;
}
while (remainder[j] > 0xffff) {
remainder[j] -= 0x10000;
remainder[j - 1] += 1;
}
}
borrow = 0;
while (remainder[0] > 0xffff) {
remainder[0] += 0x10000;
borrow++;
}
if (borrow) { /* Remainder has changed sign. */
negative = 1;
j = 4;
while (remainder[j] == 0)
j--;
remainder[j] = 0x10000 - remainder[j];
for (j--; j >= 0; j--) { /* Complement remainder. */
remainder[j] = 0xffff - remainder[j];
}
}
}
}
/* Quotient so far is exact iff remainder+quotient+2**-67 <= 0. */
if (negative) { /* Maybe exact. */
for (j = 0; j <= 4; j++) {
remainder[j] -= quotient[j];
}
SUBBIT(remainder, 67);
for (j = 4; j >= 1; j--) { /* Force borrows. */
while (remainder[j] > 0xffff) {
remainder[j] += 0x10000;
remainder[j - 1] -= 1;
}
}
if ((remainder[1] | remainder[2] | remainder[3] | remainder[4]) == 0) { /* Remainder is exactly
* zero. */
negative = 0;
} else if (remainder[0] > 0xffff) { /* Remainder has changed
* sign. */
negative = 0;
j = 4;
while (remainder[j] == 0)
j--;
remainder[j] = -remainder[j];
for (; j >= 0; j--) { /* Complement remainder. */
remainder[j] = 0xffffffff - remainder[j];
}
}
}
if (!negative &&
((remainder[0] | remainder[1] | remainder[2] | remainder[3] | remainder[4]) != 0)) { /* Remainder is neither
* negative or zero and
* therefore inexact. */
quotient[4] |= 1;
}
pz->significand[0] = ((quotient[0]) << 16) | quotient[1];
pz->significand[1] = ((quotient[2]) << 16) | quotient[3];
pz->significand[2] = ((quotient[4]) << 16);
}
void
_fp_sqrt(px, pz)
unpacked *px, *pz;
{ /* *pz gets sqrt(*px) */
*pz = *px;
switch (px->fpclass) {
case fp_quiet:
case fp_signaling:
case fp_zero:
return;
case fp_infinity:
if (px->sign == 1) { /* sqrt(-inf) */
fpu_error_nan(pz);
pz->fpclass = fp_quiet;
}
return;
case fp_normal:
if (px->sign == 1) { /* sqrt(-norm) */
fpu_error_nan(pz);
pz->fpclass = fp_quiet;
return;
}
}
/* Now x is normal. */
if (px->exponent & 1) { /* sqrt(1.f * 2**odd) = sqrt (0.5f) *
* 2**(odd+1)/2 */
pz->exponent = (px->exponent - 1) / 2;
} else { /* sqrt(1.f * 2**even) = sqrt (1.f) *
* 2**(even)/2 */
fpu_rightshift(px, 1); /* denormalize by 1 */
pz->exponent = px->exponent / 2;
}
/*
* Exponent is now correct unless sqrt rounds up to 2.0 - which can
* happen in round to positive infinity mode.
*/
dosqrt(px, pz);
}
#endif /* lint */